package com.csii.activiti.server.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.csii.activiti.server.abstraction.constant.MessageType;
import com.csii.activiti.server.abstraction.entity.ActFlowRemoteCallback;
import com.csii.activiti.server.abstraction.entity.ActReceivedBy;
import com.csii.activiti.server.abstraction.entity.ActSendMessage;
import com.csii.activiti.server.abstraction.entity.ActUserDetail;
import com.csii.activiti.server.abstraction.lock.ActLockService;
import com.csii.activiti.server.abstraction.service.ActBasicService;
import com.csii.activiti.server.abstraction.service.ActMessageService;
import com.csii.activiti.server.core.constant.*;
import com.csii.activiti.server.core.engine.EngineService;
import com.csii.activiti.server.core.entity.*;
import com.csii.activiti.server.core.entity.db.*;
import com.csii.activiti.server.core.exception.RequestParamException;
import com.csii.activiti.server.core.listener.base.BaseSimpleTaskListener;
import com.csii.activiti.server.core.listener.enums.TaskOperateEnum;
import com.csii.activiti.server.core.mapper.*;
import com.csii.activiti.server.core.service.FlowCallbackManagementService;
import com.csii.activiti.server.core.service.FlowDataManagementService;
import com.csii.activiti.server.core.service.FlowOperationService;
import com.csii.activiti.server.core.smart.process.ConvertFlowToBpmn;
import com.csii.activiti.server.core.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FlowOperationServiceImpl implements FlowOperationService {

    @Autowired
    private ActFlowConfigurationMapper actFlowConfigurationMapper;

    @Autowired
    private ActFlowFormMapper actFlowFormMapper;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ActFlowNodeMapper actFlowNodeMapper;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private ActBasicService actBasicService;

    @Autowired
    private ActFlowDelegateTaskMapper actFlowDelegateTaskMapper;

    @Autowired
    private ActFlowPublishConfigurationMapper actFlowPublishConfigurationMapper;

    @Autowired
    private ActFlowPermissionMapper actFlowPermissionMapper;

    @Autowired
    private ActMessageService actMessageService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ActFlowGroupMapper actFlowGroupMapper;

    @Autowired
    private ActLockService actLockService;

    @Autowired
    private ActExtensionMapper actExtensionMapper;

    @Autowired
    private FlowDataManagementService flowDataManagementService;

    @Autowired
    private FlowCallbackManagementService flowCallbackManagementService;

    @Autowired
    private EngineService engineService;

    @Autowired(required = false)
    private List<BaseSimpleTaskListener> baseSimpleTaskListenerList;

    @Autowired
    private ActFlowRegisterMapper flowRegisterMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAndPublishFlow(ActFlowConfiguration flow) {
        flow.setStatus(ActFlowPublishStatusConstant.PUBLISHED);
        flow.setPublish(true);
        saveFlowEntity(flow);
        publishFlow(flow);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ActFlowConfiguration saveFlow(ActFlowConfiguration flow) {
        flow.setStatus(ActFlowPublishStatusConstant.SAVE_UNPUBLISHED);
        saveFlowEntity(flow);
        return flow;
    }

    private void saveFlowEntity(ActFlowConfiguration flow){
        //验证
        if (flow.getFlowName() == null) {
            throw new RequestParamException("流程名称不能为空");
        }
        String currentTenantId = actBasicService.getCurrentTenantId();
        LambdaQueryWrapper<ActFlowConfigurationEntity> wrapper = new LambdaQueryWrapper<ActFlowConfigurationEntity>().eq(ActFlowConfigurationEntity::getFlowName, flow.getFlowName());
        wrapper.eq(ActFlowConfigurationEntity::getActTenantId,currentTenantId);
        if (flow.getId() != null){
            wrapper.ne(ActFlowConfigurationEntity::getId,flow.getId());
        }
        Integer selectCount = actFlowConfigurationMapper.selectCount(wrapper);
        if (selectCount > 0){
            throw new RequestParamException("流程名称不能重复");
        }

        String username = actBasicService.getCurrentLoginUser().getUsername();
        flow.setLastUpdateTime(new Date());
        flow.setLastUpdateUsername(username);
        if (flow.getId() != null){
            //编辑
            actFlowConfigurationMapper.updateById(new ActFlowConfigurationEntity(flow));
            return;
        }
        //新增
        //没有key添加key
        if (flow.getFlowKey() == null) {
            flow.setFlowKey(ShortUUID.randomUUID());
        }else {
            Integer count = actFlowConfigurationMapper.selectCount(new LambdaQueryWrapper<ActFlowConfigurationEntity>().eq(ActFlowConfigurationEntity::getFlowKey, flow.getFlowKey()).eq(ActFlowConfigurationEntity::getActTenantId,currentTenantId));
            if (count != 0){
                throw new RequestParamException("流程key不能重复");
            }
        }
        //状态
        if(flow.getStatus() == null){
            flow.setStatus(ActFlowPublishStatusConstant.SAVE_UNPUBLISHED);
        }
        //排序
        int sort = actFlowConfigurationMapper.queryGroupMaxSort(flow.getGroupId(),currentTenantId);
        flow.setSort(++sort);
        ActFlowConfigurationEntity actFlowConfigurationEntity = new ActFlowConfigurationEntity(flow);
        actFlowConfigurationEntity.setActTenantId(currentTenantId);
        actFlowConfigurationMapper.insert(actFlowConfigurationEntity);
        flow.setId(actFlowConfigurationEntity.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishFlow(String flowId) {
        ActFlowConfiguration flow = actFlowConfigurationMapper.selectById(flowId).toActFlowConfiguration();
        ActFlowConfigurationEntity actFlowConfigurationEntity = new ActFlowConfigurationEntity();
        actFlowConfigurationEntity.setId(flowId);
        actFlowConfigurationEntity.setPublish(true);
        actFlowConfigurationEntity.setStatus(ActFlowPublishStatusConstant.PUBLISHED);
        actFlowConfigurationMapper.updateById(actFlowConfigurationEntity);
        flow.setId(flowId);
        publishFlow(flow);
    }

    private void publishFlow(ActFlowConfiguration flow){
        String currentTenantId = actBasicService.getCurrentTenantId();
        //保存节点数据
        List<ActFlowNode> allFlowNode = flow.allFlowNode();
        if (CollUtil.isNotEmpty(allFlowNode) && !allFlowNode.stream().filter(item-> !FlowNodeTypeConstant.LINK_NODE.equals(item.getNodeType())).collect(Collectors.toList()).isEmpty()){
            List<ActFlowNodeEntity> actFlowNodeEntities = new ArrayList<>();
            ActFlowNodeEntity actFlowNodeEntity = null;
            for (ActFlowNode actFlowNode : allFlowNode) {
                String id = actFlowNode.getNodeType() + IdUtils.getId();
                actFlowNode.setId(id);
                //配置信息覆盖
                if (!FlowNodeTypeConstant.LINK_NODE.equals(actFlowNode.getNodeType()) && actFlowNode.getConfigurationItem() != null){
                    actFlowNode.getConfigurationItem().coverageIsNullCurrent(flow.getFlowConfigurationItem());
                    //为流程催办设置ID
                    if (actFlowNode.getConfigurationItem().getFlowUrgingConfiguration() != null) {
                        actFlowNode.getConfigurationItem().getFlowUrgingConfiguration().setId(FlowNodeTypeConstant.URGING_NODE + IdUtils.getId());
                    }
                    //为自动审批设置ID
                    if (actFlowNode.getConfigurationItem().getFlowAutoApprovalConfiguration() != null){
                        actFlowNode.getConfigurationItem().getFlowAutoApprovalConfiguration().setId(FlowNodeTypeConstant.AUTO_NODE + IdUtils.getId());
                    }
                }
                //判断是不是发起人自选
                if (FlowNodeVariableTypeConstant.OPTIONAL.equals(actFlowNode.getVariable())){
                    actFlowNode.setVariableValue(id);
                }
                actFlowNodeEntity = new ActFlowNodeEntity();
                actFlowNodeEntity.setId(id);
                actFlowNodeEntity.setJsonData(JSONObject.toJSONString(actFlowNode));
                actFlowNodeEntity.setNodeName(actFlowNode.getNodeName());
                actFlowNodeEntity.setFlowKey(flow.getFlowKey());
                //或签和并签显示名称处理
                if (FlowNodeTypeConstant.APPROVER.equals(actFlowNode.getNodeType()) ||FlowNodeTypeConstant.EXECUTOR.equals(actFlowNode.getNodeType())){
                    String approvalMechanismName = ApprovalConfigConstant.OR_SIGN.equals(actFlowNode.getConfigurationItem().getApprovalMechanism()) ? "-或签":"-会签";
                    actFlowNodeEntity.setNodeName(actFlowNode.getNodeName() + approvalMechanismName);
                    actFlowNode.setNodeName(actFlowNodeEntity.getNodeName());
                }

                actFlowNodeEntity.setNodeType(actFlowNode.getNodeType());
                actFlowNodeEntities.add(actFlowNodeEntity);
            }
            //批量写入节点
            actFlowNodeMapper.batchInsert(actFlowNodeEntities);

        }
        //转换activiti识别对象
        BpmnModel bpmnModel = new ConvertFlowToBpmn(flow).getBpmnModel();
        //部署模型
        DeploymentBuilder deployment = repositoryService.createDeployment();
        deployment.tenantId(currentTenantId);
        deployment.name(flow.getFlowName());
        deployment.key(flow.getFlowKey());
        deployment.addBpmnModel(flow.getFlowKey()+".bpmn20.xml",bpmnModel);
        Deployment deploy = deployment.deploy();
        String definitionId = deploy.getId();
        //判断模式
        boolean isFormPattern = ApprovalConfigConstant.PATTERN_FORM.equals(flow.getPattern());
        if (isFormPattern){
            //绑定表单
            ActFlowFormEntity actFlowFormEntity = new ActFlowFormEntity();
            actFlowFormEntity.setId(definitionId);
            actFlowFormEntity.setJsonData(flow.getFormJson());
            actFlowFormMapper.insert(actFlowFormEntity);
            //绑定发起人节点
            ActFlowNodeEntity actFlowNodeEntity = new ActFlowNodeEntity();
            actFlowNodeEntity.setId(definitionId);
            actFlowNodeEntity.setJsonData(JSONObject.toJSONString(flow.getInitiatorFormContentSetting()));
            actFlowNodeEntity.setFlowKey(flow.getFlowKey());
            actFlowNodeMapper.insert(actFlowNodeEntity);
        }
        JSONObject formJson = JSONObject.parseObject(flow.getFormJson());
        //绑定已发布配置
        actFlowPublishConfigurationMapper.insert(new ActFlowPublishConfigEntity(definitionId,flow.getFlowName(),flow.getFlowKey(),flow.getIconType(),flow.getDescription(),JSONObject.toJSONString(flow),flow.getSummary(),FormJsonProcessUtils.recursionManyConditionsResultString(formJson)));

        //查询上次配置信息
        List<ActCommonDataEntity> originalCommonDataList = null;
        if (isFormPattern){
            ActFlowConfigurationEntity lastActFlowConfiguration = actFlowConfigurationMapper.selectOne(new LambdaQueryWrapper<ActFlowConfigurationEntity>().select(ActFlowConfigurationEntity::getFlowColumnJson, ActFlowConfigurationEntity::getLastDeploymentId).eq(ActFlowConfigurationEntity::getId, flow.getId()));
            if (lastActFlowConfiguration != null){
                originalCommonDataList = lastActFlowConfiguration.toColumnData();
                if (originalCommonDataList == null){
                    ActFlowFormEntity actFlowFormEntity = actFlowFormMapper.selectById(lastActFlowConfiguration.getLastDeploymentId());
                    if (actFlowFormEntity != null){
                        originalCommonDataList = FormJsonProcessUtils.formJsonProcessToCommonData(JSONObject.parseObject(actFlowFormEntity.getJsonData()));
                    }else{
                        originalCommonDataList = new ArrayList<>();
                    }
                }
            }else{
                originalCommonDataList = new ArrayList<>();
            }
        }

        //更新最后部署ID
        ActFlowConfigurationEntity actFlowConfigurationEntity = new ActFlowConfigurationEntity();
        actFlowConfigurationEntity.setId(flow.getId());
        actFlowConfigurationEntity.setLastDeploymentId(definitionId);
        actFlowConfigurationMapper.updateById(actFlowConfigurationEntity);

        if (isFormPattern){
            List<ActCommonDataEntity> currentCommonDataList = FormJsonProcessUtils.formJsonProcessToCommonData(formJson);
            //修改数据信息 ddl语句会默认提交事务 所以放到最后
            flowDataManagementService.publishDataProcess(originalCommonDataList,currentCommonDataList,flow.getFlowKey(),flow.getFlowName());
            //更新表数据json
            actFlowConfigurationEntity.setFlowColumnJson(JSONObject.toJSONString(currentCommonDataList));
            actFlowConfigurationEntity.setLastDeploymentId(null);
            actFlowConfigurationMapper.updateById(actFlowConfigurationEntity);
        }


    }

    @Override
    public String startFlowInstanceByKey(ActStartFlowInstance actStartFlowInstance) {
        if (actStartFlowInstance.getFlowKey() == null){
            throw new RequestParamException("流程key不能为空");
        }
        String currentTenantId = actBasicService.getCurrentTenantId();
        ActFlowConfigurationEntity actFlowConfigurationEntity = actFlowConfigurationMapper.selectOne(new LambdaQueryWrapper<ActFlowConfigurationEntity>().select(ActFlowConfigurationEntity::getPublish,ActFlowConfigurationEntity::getResubmitRule).eq(ActFlowConfigurationEntity::getFlowKey, actStartFlowInstance.getFlowKey()).eq(ActFlowConfigurationEntity::getActTenantId,currentTenantId));
        if (!actFlowConfigurationEntity.getPublish()){
            throw new RequestParamException("流程已停用或者未发布无法提交");
        }
        String initiator = null;
        String iframeUrl = null;
        //判断是不是iframe模式
        if (actStartFlowInstance instanceof ActStartFlowInstanceIframeUrl){
            ActStartFlowInstanceIframeUrl actStartFlowInstanceIframeUrl = (ActStartFlowInstanceIframeUrl) actStartFlowInstance;
            initiator = actStartFlowInstanceIframeUrl.getInitiator();
            iframeUrl = actStartFlowInstanceIframeUrl.getIframeUrl();
        }
        if (initiator == null){
            ActUserDetail currentLoginUser = actBasicService.getCurrentLoginUser();
            initiator = currentLoginUser.getUsername();
        }
        if (initiator == null){
            throw new RequestParamException("流程申请人不能为空");
        }

        // 启动流程用户
        identityService.setAuthenticatedUserId(initiator);
        //启动流程
        Map<String, Object> variables = new HashMap<>();
        if(actStartFlowInstance.getParentProcessInstanceId() != null && actStartFlowInstance.getFormData() != null){
            HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(actStartFlowInstance.getParentProcessInstanceId()).variableName(CommonConstant.FORM_DATA).singleResult();
            Map<String, Object> oldFormData = (Map<String, Object>) historicVariableInstance.getValue();
            if (oldFormData != null){
                oldFormData.putAll(actStartFlowInstance.getFormData());
                actStartFlowInstance.setFormData(oldFormData);
            }

        }

        //将表单数据放入流程变量里
        variables.put(CommonConstant.FORM_DATA,actStartFlowInstance.getFormData());
        //iframe模式
        if (iframeUrl != null){
            variables.put(CommonConstant.IFRAME_URL,iframeUrl);
        }
        if (CollUtil.isNotEmpty(actStartFlowInstance.getCallbackList())){
            variables.put(CommonConstant.REMOTE_URL,actStartFlowInstance.getCallbackList());
        }
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId(actStartFlowInstance.getFlowKey(), variables,currentTenantId);
        //先判断下流程是否结束,没有结束就设置流程名称
//        if (runtimeService.createProcessInstanceQuery().processInstanceId(processInstance.getId()).singleResult() != null){
//            runtimeService.setProcessInstanceName(processInstance.getId(), processInstance.getProcessDefinitionName());
//        }
        if (FlowResubmitRuleConstant.REPLACE_FORM.equals(actFlowConfigurationEntity.getResubmitRule()) && actStartFlowInstance.getParentProcessInstanceId() != null){
            ActFlowRegisterEntity actFlowRegisterEntity = new ActFlowRegisterEntity();
            actFlowRegisterEntity.setId(processInstance.getId());
            actFlowRegisterEntity.setParentId(actStartFlowInstance.getParentProcessInstanceId());
            flowRegisterMapper.insert(actFlowRegisterEntity);
        }

        flowDataManagementService.addData(processInstance.getId());
        return processInstance.getId();
    }

    @Override
    public void completeTask(ActCompleteTask actCompleteTask) {
        boolean updateDataManage = false;
        Task task = taskService.createTaskQuery().taskId(actCompleteTask.getTaskId()).singleResult();
        if (task == null){
            throw new RequestParamException("待办不存在或待办已审批");
        }
        //加锁key
        String lockKey = task.getProcessInstanceId();
        //加锁
        actLockService.lock(lockKey);
        try {
            task = taskService.createTaskQuery().taskId(actCompleteTask.getTaskId()).singleResult();
            if (task == null){
                throw new RequestParamException("待办不存在或待办已审批");
            }
            if (StrUtil.isEmpty(actCompleteTask.getCommand())){
                actCompleteTask.setCommand(" ");
            }
            String id = task.getTaskDefinitionKey();
            ActFlowNodeEntity actFlowNodeEntity = actFlowNodeMapper.selectById(id);
            ActFlowNode actFlowNode = actFlowNodeEntity.transitionActFlowNode();

            //添加评论
            identityService.setAuthenticatedUserId(task.getAssignee());
            taskService.addComment(task.getId(),task.getProcessInstanceId(),actCompleteTask.getCommand());
            //数字签名
            if (actFlowNode.getConfigurationItem().isDigitalSignature()){
                if (actCompleteTask.getSignature() != null){
                    taskService.addComment(task.getId(),task.getProcessInstanceId(),CommonConstant.SIGNATURE_TYPE,actCompleteTask.getSignature());
                }
            }
            Map copyFormData = null;
            if (CollUtil.isNotEmpty(actCompleteTask.getFormData())) {
                Map formData = (Map) taskService.getVariable(task.getId(), CommonConstant.FORM_DATA);
                copyFormData = new HashMap(formData);
                formData.putAll(actCompleteTask.getFormData());
                taskService.setVariable(task.getId(),CommonConstant.FORM_DATA,formData);
                updateDataManage = true;
            }

            try {
                //完成任务
                engineService.complete(task.getId());
            }catch (Exception e){
                //异常情况回滚
                log.error("task auto complete is error task:{} e:{}",task,e);
                taskService.deleteComments(task.getId(),task.getProcessInstanceId());
                if (copyFormData != null){
                    taskService.setVariable(task.getId(),CommonConstant.FORM_DATA,copyFormData);
                    updateDataManage = false;
                }
                throw new RequestParamException("流程审批异常,因为调整表单参数,导致流程无法正常结束");
            }
        }finally {
            actLockService.unlock(lockKey);
        }
        //如果表达数据有变动，更新数据管理
        flowDataManagementService.addData(task.getProcessInstanceId());
        //监听通知
        if (baseSimpleTaskListenerList != null){
            for (BaseSimpleTaskListener baseSimpleTaskListener : baseSimpleTaskListenerList) {
                baseSimpleTaskListener.notify(task, TaskOperateEnum.AGREE);
            }
        }


    }

    @Override
    public void backTask(ActBackTask actBackTask) {
        Task task = taskService.createTaskQuery().taskId(actBackTask.getTaskId()).singleResult();
        if (task == null){
            throw new RequestParamException("待办不存在或待办已审批");
        }
        //加锁key
        String lockKey = task.getProcessInstanceId();
        //加锁
        actLockService.lock(lockKey);
        try {
            task = taskService.createTaskQuery().taskId(actBackTask.getTaskId()).singleResult();
            if (task == null){
                throw new RequestParamException("待办不存在或待办已审批");
            }

            if (StrUtil.isEmpty(actBackTask.getCommand())){
                actBackTask.setCommand(" ");
            }
            identityService.setAuthenticatedUserId(task.getAssignee());
            taskService.addComment(task.getId(),task.getProcessInstanceId(),actBackTask.getCommand());
            Map formData = (Map) taskService.getVariable(task.getId(), CommonConstant.FORM_DATA);
            if (CollUtil.isNotEmpty(actBackTask.getFormData())) {
                formData.putAll(actBackTask.getFormData());
                taskService.setVariable(task.getId(),CommonConstant.FORM_DATA,formData);
            }
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            List<ActFlowRemoteCallback> callbackVariableInstance = (List<ActFlowRemoteCallback>) taskService.getVariable(task.getId(), CommonConstant.REMOTE_URL);

            engineService.deleteProcessInstance(task.getProcessInstanceId(), ActFlowActionSettingConstant.REJECT);
            //写入数据库
            flowDataManagementService.addData(task.getProcessInstanceId());
            ActSendMessage sendMessage = new ActSendMessage();
            sendMessage.setTenantId(historicProcessInstance.getTenantId());
            sendMessage.setProcessName(historicProcessInstance.getProcessDefinitionName());
            sendMessage.setProcessDefinitionId(task.getProcessDefinitionId());
            sendMessage.setProcessKey(historicProcessInstance.getProcessDefinitionKey());
            sendMessage.setProcessInstanceId(task.getProcessInstanceId());
            sendMessage.setInitiator(historicProcessInstance.getStartUserId());
            sendMessage.setFormData(formData);
            sendMessage.setReceivedByList(CollUtil.newArrayList(new ActReceivedBy(null,historicProcessInstance.getStartUserId())));
            sendMessage.setCurrentNodeId(task.getTaskDefinitionKey());
            sendMessage.setCurrentNodeName(task.getName());
            sendMessage.setCurrentApprove(task.getAssignee());
            sendMessage.setApproveOpinion(actBackTask.getCommand());
            if (callbackVariableInstance != null){
                sendMessage.setCallbackList(callbackVariableInstance);
            }
            sendMessage.setCurrentDate(new Date());
            String deploymentId = historicProcessInstance.getDeploymentId();
            ActFlowPublishConfigEntity flowPublish = actFlowPublishConfigurationMapper.selectOne(new LambdaQueryWrapper<ActFlowPublishConfigEntity>().select(ActFlowPublishConfigEntity::getId, ActFlowPublishConfigEntity::getIconType,ActFlowPublishConfigEntity::getSummary,ActFlowPublishConfigEntity::getManyConditionJson).eq(ActFlowPublishConfigEntity::getId, deploymentId));
            if (flowPublish != null){
                sendMessage.setIconType(flowPublish.getIconType());
                sendMessage.setSummary(ELUtils.getSummary(flowPublish.getSummary(),flowPublish.getManyConditionJson(),formData));
            }
            actMessageService.sendMessage(sendMessage, MessageType.reject);
            //触发回调
            flowCallbackManagementService.callback(sendMessage,MessageType.reject.getType());
            //监听通知
            if (baseSimpleTaskListenerList != null){
                for (BaseSimpleTaskListener baseSimpleTaskListener : baseSimpleTaskListenerList) {
                    baseSimpleTaskListener.notify(task, TaskOperateEnum.REJECT);
                }
            }
        }finally {
            actLockService.unlock(lockKey);
        }
    }

    @Override
    public void delegateTask(ActDelegateTask actDelegateTask) {
        Task task = taskService.createTaskQuery().taskId(actDelegateTask.getTaskId()).singleResult();
        String assignee = task.getAssignee();
        if (task.getOwner() != null) {
            taskService.setOwner(actDelegateTask.getTaskId(),assignee);
        }
        taskService.setAssignee(actDelegateTask.getTaskId(),actDelegateTask.getUsernameDelegate());
        //记录转交记录
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        ActFlowDelegateTaskEntity actFlowDelegateTaskEntity = new ActFlowDelegateTaskEntity();
        actFlowDelegateTaskEntity.setTaskId(actDelegateTask.getTaskId());
        actFlowDelegateTaskEntity.setTargetUsername(actDelegateTask.getUsernameDelegate());
        actFlowDelegateTaskEntity.setCurrentUsername(assignee);
        actFlowDelegateTaskEntity.setCreateTime(new Date());
        actFlowDelegateTaskEntity.setNodeType(task.getTaskDefinitionKey());
        actFlowDelegateTaskEntity.setNodeName(task.getName());
        actFlowDelegateTaskEntity.setInitiator(historicProcessInstance.getStartUserId());
        actFlowDelegateTaskEntity.setProcessName(historicProcessInstance.getProcessDefinitionName());
        actFlowDelegateTaskMapper.insert(actFlowDelegateTaskEntity);
        Map formData = (Map) taskService.getVariable(task.getId(), CommonConstant.FORM_DATA);
        List<ActFlowRemoteCallback> callbackVariableInstance = (List<ActFlowRemoteCallback>) taskService.getVariable(task.getId(), CommonConstant.REMOTE_URL);


        ActSendMessage sendMessage = new ActSendMessage();
        sendMessage.setTenantId(historicProcessInstance.getTenantId());
        sendMessage.setProcessName(historicProcessInstance.getProcessDefinitionName());
        sendMessage.setProcessDefinitionId(task.getProcessDefinitionId());
        sendMessage.setProcessKey(historicProcessInstance.getProcessDefinitionKey());
        sendMessage.setProcessInstanceId(task.getProcessInstanceId());
        sendMessage.setInitiator(historicProcessInstance.getStartUserId());
        sendMessage.setFormData(formData);
        sendMessage.setReceivedByList(CollUtil.newArrayList(new ActReceivedBy(null,historicProcessInstance.getStartUserId())));
        sendMessage.setCurrentNodeId(task.getTaskDefinitionKey());
        sendMessage.setCurrentNodeName(task.getName());
        if (callbackVariableInstance != null){
            sendMessage.setCallbackList(callbackVariableInstance);
        }
        sendMessage.setCurrentDate(new Date());
        String deploymentId = historicProcessInstance.getDeploymentId();
        ActFlowPublishConfigEntity flowPublish = actFlowPublishConfigurationMapper.selectOne(new LambdaQueryWrapper<ActFlowPublishConfigEntity>().select(ActFlowPublishConfigEntity::getId, ActFlowPublishConfigEntity::getIconType,ActFlowPublishConfigEntity::getSummary,ActFlowPublishConfigEntity::getManyConditionJson).eq(ActFlowPublishConfigEntity::getId, deploymentId));
        if (flowPublish != null){
            sendMessage.setIconType(flowPublish.getIconType());
            sendMessage.setSummary(ELUtils.getSummary(flowPublish.getSummary(),flowPublish.getManyConditionJson(),formData));
        }
        actMessageService.sendMessage(sendMessage, MessageType.transfer);
        //触发回调
        flowCallbackManagementService.callback(sendMessage,MessageType.transfer.getType());


        //监听通知
        if (baseSimpleTaskListenerList != null){
            for (BaseSimpleTaskListener baseSimpleTaskListener : baseSimpleTaskListenerList) {
                baseSimpleTaskListener.notify(task, TaskOperateEnum.TRANSFER);
            }
        }
    }

    @Override
    public void addFlowPermission(ActFlowPermission actFlowPermission) {
        String flowId = actFlowPermission.getFlowId();
        List<ActFlowPermissionEntity> dataList = new ArrayList<>();
        if (CollUtil.isNotEmpty(actFlowPermission.getDeptList())){
            dataList.addAll(actFlowPermission.getDeptList().stream().map(item -> new ActFlowPermissionEntity(null, flowId, ActFlowPermissionConstant.DEPT, item.getDeptCode())).collect(Collectors.toList()));
        }
        if (CollUtil.isNotEmpty(actFlowPermission.getRoleList())){
            dataList.addAll(actFlowPermission.getRoleList().stream().map(item -> new ActFlowPermissionEntity(null, flowId, ActFlowPermissionConstant.ROLE, item.getRoleCode())).collect(Collectors.toList()));
        }
        if (CollUtil.isNotEmpty(actFlowPermission.getUserlist())){
            dataList.addAll(actFlowPermission.getUserlist().stream().map(item -> new ActFlowPermissionEntity(null, flowId, ActFlowPermissionConstant.USER, item.getUsername())).collect(Collectors.toList()));
        }

        actFlowPermissionMapper.delete(new LambdaQueryWrapper<ActFlowPermissionEntity>().eq(ActFlowPermissionEntity::getFlowId,flowId));
        if (!dataList.isEmpty()){
            actFlowPermissionMapper.batchInsert(dataList);
        }
    }


    @Override
    public void batchUpdateFlowSort(List<String> ids) {
        if (CollUtil.isEmpty(ids)){
            throw new RequestParamException("排序参数不能为空");
        }
        List<ActFlowConfigurationEntity> list = new ArrayList<>();
        int sort = 1;
        for (String id : ids) {
            ActFlowConfigurationEntity actFlowConfigurationEntity = new ActFlowConfigurationEntity();
            actFlowConfigurationEntity.setId(id);
            actFlowConfigurationEntity.setSort(sort++);
            list.add(actFlowConfigurationEntity);
        }
        actFlowConfigurationMapper.batchUpdateFlowSort(list);

    }

    @Override
    public void completeMessageTask(ActMessageTask actMessageTask) {
        Task task = taskService.createTaskQuery().processInstanceId(actMessageTask.getInstanceId()).taskAssignee(CommonConstant.MESSAGE_PREFIX_KEY + actMessageTask.getKey()).singleResult();
        if (task == null){
            throw new RequestParamException("待办不存在或待办已审批");
        }
        //加锁key
        String lockKey = task.getProcessInstanceId();
        //加锁
        actLockService.lock(lockKey);
        try {
            task = taskService.createTaskQuery().processInstanceId(actMessageTask.getInstanceId()).taskAssignee(CommonConstant.MESSAGE_PREFIX_KEY + actMessageTask.getKey()).singleResult();
            if (task == null){
                throw new RequestParamException("待办不存在或待办已审批");
            }

            if (StrUtil.isEmpty(actMessageTask.getCommand())){
                actMessageTask.setCommand(" ");
            }
            identityService.setAuthenticatedUserId(task.getAssignee());
            //添加评论
            taskService.addComment(task.getId(),task.getProcessInstanceId(),actMessageTask.getCommand());
            //完成任务
            engineService.complete(task.getId());
        }finally {
            actLockService.unlock(lockKey);
        }

    }

    @Override
    public void backMessageTask(ActMessageTask actMessageTask) {
        Task task = taskService.createTaskQuery().processInstanceId(actMessageTask.getInstanceId()).taskAssignee(CommonConstant.MESSAGE_PREFIX_KEY + actMessageTask.getKey()).singleResult();
        backTask(new ActBackTask(task.getId(),actMessageTask.getCommand()));
    }

    @Override
    public void moveToGroup(ActFlowMoveToGroup actFlowMoveToGroup) {
        if (StrUtil.isBlank(actFlowMoveToGroup.getFlowId()) || StrUtil.isBlank(actFlowMoveToGroup.getGroupId())){
            throw new RequestParamException("参数异常");
        }
        ActFlowConfigurationEntity actFlowConfigurationEntity = new ActFlowConfigurationEntity();
        actFlowConfigurationEntity.setId(actFlowMoveToGroup.getFlowId());
        actFlowConfigurationEntity.setGroupId(actFlowMoveToGroup.getGroupId());
        actFlowConfigurationMapper.updateById(actFlowConfigurationEntity);
    }

    @Override
    public void deleteFlow(String flowId) {
        LambdaQueryWrapper<ActFlowConfigurationEntity> wrapper = new LambdaQueryWrapper<ActFlowConfigurationEntity>().select(ActFlowConfigurationEntity::getId,ActFlowConfigurationEntity::getFlowKey,ActFlowConfigurationEntity::getPublish).eq(ActFlowConfigurationEntity::getId,flowId);
        ActFlowConfigurationEntity actFlowConfigurationEntity = actFlowConfigurationMapper.selectOne(wrapper);
        long count = taskService.createTaskQuery().processDefinitionKey(actFlowConfigurationEntity.getFlowKey()).count();
        if (count >0){
            throw new RequestParamException("该流程还有未走完成的实例,无法删除");
        }
        actFlowConfigurationMapper.deleteById(flowId);
        //考虑还有历史数据,不需要删除全部数据
//        if (actFlowConfigurationEntity.getPublish()){
//            List<Deployment> list = repositoryService.createDeploymentQuery().processDefinitionKey(actFlowConfigurationEntity.getFlowKey()).list();
//            List<String> deploymentIdList = list.stream().map(Deployment::getId).collect(Collectors.toList());
//
//            //删除表单
//            actFlowFormMapper.deleteBatchIds(deploymentIdList);
//            //删除节点
//            actFlowNodeMapper.delete(new LambdaQueryWrapper<ActFlowNodeEntity>().eq(ActFlowNodeEntity::getFlowKey,actFlowConfigurationEntity.getFlowKey()));
//
//            repositoryService.deleteDeployment(deploymentIdList.get(0),true);
//        }


    }

    @Override
    public void updatePublishStatus(String flowId,String groupId) {
        LambdaQueryWrapper<ActFlowConfigurationEntity> wrapper = new LambdaQueryWrapper<ActFlowConfigurationEntity>().select(ActFlowConfigurationEntity::getId,ActFlowConfigurationEntity::getPublish).eq(ActFlowConfigurationEntity::getId,flowId);
        ActFlowConfigurationEntity actFlowConfigurationEntity = actFlowConfigurationMapper.selectOne(wrapper);
        if (actFlowConfigurationEntity.getPublish() == null) {
            throw new RequestParamException("该流程还未发布,无法启动");
        }
        if (actFlowConfigurationEntity.getPublish()){
            actFlowConfigurationEntity.setGroupId("-1");
        }
        if (StrUtil.isNotBlank(groupId)){
            actFlowConfigurationEntity.setGroupId(groupId);
        }
        actFlowConfigurationEntity.setPublish(actFlowConfigurationEntity.getPublish() ? false:true);
        actFlowConfigurationMapper.updateById(actFlowConfigurationEntity);
    }

    @Override
    public void reapply(String flowInstanceId) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(flowInstanceId).singleResult();
        String processDefinitionKey = historicProcessInstance.getProcessDefinitionKey();
        HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(flowInstanceId).variableName(CommonConstant.FORM_DATA).singleResult();
        Map<String, Object> processVariables = (Map<String, Object>) historicVariableInstance.getValue();
        ActStartFlowInstance actStartFlowInstance = new ActStartFlowInstance();
        actStartFlowInstance.setFlowKey(processDefinitionKey);
        actStartFlowInstance.setFormData(processVariables);
        startFlowInstanceByKey(actStartFlowInstance);
    }

    @Override
    public void withdrawalProcess(ActFlowWithdrawn actFlowWithdrawn) {
        actLockService.lock(actFlowWithdrawn.getFlowInstanceId());
        try {
            GenericReferenceEntity<List<ActFlowProIdAndNode>, Map<String, Boolean>> listMapGenericReferenceEntity = BasicCommonUtils.queryFlowProIdAndNodeGetGroupMaxAndWithdraw(actExtensionMapper.queryFlowProIdAndNodeByInstanceIds(CollUtil.newHashSet(actFlowWithdrawn.getFlowInstanceId()), null, false));
            Map<String, Boolean> instanceIdAndWithdraw = listMapGenericReferenceEntity.getTwoData();
            Boolean withdraw = instanceIdAndWithdraw.get(actFlowWithdrawn.getFlowInstanceId());
            if (withdraw != null && !withdraw){
                throw new RequestParamException("当前流程不是在第一个节点,无法撤回");
            }
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(actFlowWithdrawn.getFlowInstanceId()).singleResult();

            HistoricVariableInstance formDataVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(actFlowWithdrawn.getFlowInstanceId()).variableName(CommonConstant.FORM_DATA).singleResult();
            Map<String, Object> formData = (Map<String, Object>) formDataVariableInstance.getValue();

            HistoricVariableInstance callbackVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(actFlowWithdrawn.getFlowInstanceId()).variableName(CommonConstant.REMOTE_URL).singleResult();
            identityService.setAuthenticatedUserId(actBasicService.getCurrentLoginUser().getUsername());
            runtimeService.setVariable(actFlowWithdrawn.getFlowInstanceId(),CommonConstant.WITHDRAWN_COMMAND,actFlowWithdrawn.getCommand());
            engineService.deleteProcessInstance(actFlowWithdrawn.getFlowInstanceId(),ActFlowStatusConstant.WITHDRAWN);
            //写入数据库
            flowDataManagementService.addData(actFlowWithdrawn.getFlowInstanceId());

            ActSendMessage sendMessage = new ActSendMessage();
            sendMessage.setTenantId(historicProcessInstance.getTenantId());
            sendMessage.setProcessName(historicProcessInstance.getProcessDefinitionName());
            sendMessage.setProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
            sendMessage.setProcessKey(historicProcessInstance.getProcessDefinitionKey());
            sendMessage.setProcessInstanceId(actFlowWithdrawn.getFlowInstanceId());
            sendMessage.setInitiator(historicProcessInstance.getStartUserId());
            sendMessage.setFormData(formData);
            List<HistoricTaskInstance> taskList = historyService.createHistoricTaskInstanceQuery().processInstanceId(actFlowWithdrawn.getFlowInstanceId()).list();
            sendMessage.setReceivedByList(taskList.stream().map(item-> new ActReceivedBy(item.getId(),item.getAssignee())).collect(Collectors.toList()));
            HistoricTaskInstance historicTaskInstance = taskList.get(0);

            sendMessage.setCurrentNodeId(historicTaskInstance.getTaskDefinitionKey());
            sendMessage.setCurrentNodeName(historicTaskInstance.getName());
            sendMessage.setCurrentDate(new Date());

            if (callbackVariableInstance != null){
                sendMessage.setCallbackList((List<ActFlowRemoteCallback>) callbackVariableInstance.getValue());
            }
            sendMessage.setCurrentDate(new Date());
            String deploymentId = historicProcessInstance.getDeploymentId();
            ActFlowPublishConfigEntity flowPublish = actFlowPublishConfigurationMapper.selectOne(new LambdaQueryWrapper<ActFlowPublishConfigEntity>().select(ActFlowPublishConfigEntity::getId, ActFlowPublishConfigEntity::getIconType,ActFlowPublishConfigEntity::getSummary,ActFlowPublishConfigEntity::getManyConditionJson).eq(ActFlowPublishConfigEntity::getId, deploymentId));
            if (flowPublish != null){
                sendMessage.setIconType(flowPublish.getIconType());
                sendMessage.setSummary(ELUtils.getSummary(flowPublish.getSummary(),flowPublish.getManyConditionJson(),formData));
            }
            actMessageService.sendMessage(sendMessage, MessageType.withdrawn);
            //触发回调
            flowCallbackManagementService.callback(sendMessage,MessageType.withdrawn.getType());

        }finally {
            actLockService.unlock(actFlowWithdrawn.getFlowInstanceId());
        }

    }

    @Override
    public void urgingProcessByInstanceId(String instanceId) {
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(instanceId).list();
        if (CollUtil.isEmpty(taskList)){
            throw new RequestParamException("流程已经结束或者无开启，无法催办");
        }
        Task task = taskList.get(0);
        long diff = System.currentTimeMillis() - task.getCreateTime().getTime();
        //判断是否大于一个小时，只有大于一个小时才能手动催办
        if(diff < (1000 * 60 * 60)){
            throw new RequestParamException("当前节点停留未超过一个小时，无法催办");
        }
        String nodeId = task.getTaskDefinitionKey();
        ActFlowNode actFlowNode = actFlowNodeMapper.selectById(nodeId).transitionActFlowNode();
        ActFlowUrgingConfiguration flowUrgingConfiguration = actFlowNode.getConfigurationItem().getFlowUrgingConfiguration();
        if (flowUrgingConfiguration == null){
            throw new RequestParamException("流程当前节点没有配置催办，无法催办");
        }
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        //ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
        ActFlowPublishConfigEntity actFlowPublishConfigEntity = actFlowPublishConfigurationMapper.selectOne(new LambdaQueryWrapper<ActFlowPublishConfigEntity>().select(ActFlowPublishConfigEntity::getIconType, ActFlowPublishConfigEntity::getFlowName,ActFlowPublishConfigEntity::getSummary,ActFlowPublishConfigEntity::getManyConditionJson).eq(ActFlowPublishConfigEntity::getId, historicProcessInstance.getDeploymentId()));
        //发送消息
        ActSendMessage sendMessage = new ActSendMessage();
        sendMessage.setTenantId(historicProcessInstance.getTenantId());
        sendMessage.setProcessName(historicProcessInstance.getProcessDefinitionName());
        sendMessage.setProcessDefinitionId(task.getProcessDefinitionId());
        sendMessage.setProcessKey(historicProcessInstance.getProcessDefinitionKey());
        sendMessage.setProcessInstanceId(task.getProcessInstanceId());
        sendMessage.setInitiator(historicProcessInstance.getStartUserId());
        HistoricVariableInstance historicFormDataVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(task.getProcessInstanceId()).variableName(CommonConstant.FORM_DATA).singleResult();
        Map<String, Object> formData = (Map<String, Object>) historicFormDataVariableInstance.getValue();
        sendMessage.setFormData(formData);
        List<ActReceivedBy> receivedByList = taskList.stream().map(item -> new ActReceivedBy(item.getId(), item.getAssignee())).collect(Collectors.toList());
        sendMessage.setReceivedByList(receivedByList);
        sendMessage.setCurrentNodeId(task.getTaskDefinitionKey());
        sendMessage.setCurrentNodeName(task.getName());
        HistoricVariableInstance callbackVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(task.getProcessInstanceId()).variableName(CommonConstant.REMOTE_URL).singleResult();
        if (callbackVariableInstance != null) {
            sendMessage.setCallbackList((List<ActFlowRemoteCallback>) callbackVariableInstance.getValue());
        }
        sendMessage.setCurrentDate(new Date());
        if (actFlowPublishConfigEntity != null){
            sendMessage.setSummary(actFlowPublishConfigEntity.getSummary());
            sendMessage.setIconType(ELUtils.getSummary(actFlowPublishConfigEntity.getSummary(),actFlowPublishConfigEntity.getManyConditionJson(),formData));
        }
        MessageType messageType = MessageType.valueOf(actFlowNode.getConfigurationItem().getFlowUrgingConfiguration().getRemindType());
        Map<String,Object> paramVariables = new HashMap<>();
        paramVariables.put("taskCreateTime",task.getCreateTime());
        //手动催办type=2
        paramVariables.put("type","2");
        sendMessage.setParamVariables(paramVariables);
        actMessageService.sendMessage(sendMessage, messageType);
        //触发回调
        flowCallbackManagementService.callback(sendMessage, messageType.getType());
    }

    @Override
    public String generateComplexKey(String simpleKey) {
        byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded();
        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
        String complexKey = aes.encryptHex(simpleKey);
        if (complexKey.length() >= 32){
            complexKey = complexKey.substring(0,32);
        }
        return complexKey;
    }

    @Override
    public void completeTaskByInstanceId(ActProcessTaskByInstanceId actProcessTaskByInstanceId) {
        String username = actBasicService.getCurrentLoginUser().getUsername();
        Task task = taskService.createTaskQuery().processInstanceId(actProcessTaskByInstanceId.getInstanceId()).taskAssignee(username).singleResult();
        completeTask(new ActCompleteTask(task.getId(),actProcessTaskByInstanceId.getCommand()));
    }

    @Override
    public void backTaskByInstanceId(ActProcessTaskByInstanceId actProcessTaskByInstanceId) {
        String username = actBasicService.getCurrentLoginUser().getUsername();
        Task task = taskService.createTaskQuery().processInstanceId(actProcessTaskByInstanceId.getInstanceId()).taskAssignee(username).singleResult();
        backTask(new ActBackTask(task.getId(),actProcessTaskByInstanceId.getCommand()));
    }


}
